package com.inspur.edp.bef.bemanager.generatecomponent.componentgenerators;


import com.inspur.edp.bef.bemanager.codegenerator.JavaCompCodeNames;
import com.inspur.edp.bef.bemanager.generatecomponent.GspMetadataExchangeUtil;
import com.inspur.edp.bef.bemanager.util.CheckInfoUtil;
import com.inspur.edp.bef.bizentity.beenum.BEOperationType;
import com.inspur.edp.bef.bizentity.exceptions.BusinessEntityErrorCodeEnum;
import com.inspur.edp.bef.bizentity.exceptions.BusinessEntityException;
import com.inspur.edp.bef.bizentity.operation.BizOperation;
import com.inspur.edp.bef.component.base.GspComponent;
import com.inspur.edp.lcm.metadata.api.entity.GspMetadata;
import com.inspur.edp.lcm.metadata.api.entity.MetadataReference;
import com.inspur.edp.lcm.metadata.api.service.MetadataService;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import java.util.Objects;

/**
 * 构件元数据生成器基类
 */
public abstract class BaseComponentGenerator {
    /**
     * 业务实体编号
     */
    protected String bizEntityCode;
    /**
     * 业务实体程序集名称
     */
    protected String assemblyName;
    protected String nameSpace;
    /**
     * 是否当前生成的构件为子节点的构件
     */
    protected boolean isChildObj;
    /**
     * 节点编号
     */
    protected String objCode;
    protected String bizObjectID;
    /**
     * 原始构件
     */
    protected GspComponent originalComponent;

    /**
     * 生成构件元数据
     *
     * @param operation     业务操作
     * @param path          生成指定路径
     * @param bizEntityCode 业务实体编号
     * @param assemblyName  业务实体程序集名称
     * @param isChildObj    是否子节点
     * @param objCode       节点对象编号
     * @param bizObjectID   业务对象ID
     * @param metadata      元数据
     */
    public final String generateComponent(BizOperation operation, String path, String bizEntityCode,
        String assemblyName, boolean isChildObj, String objCode, String bizObjectID,
        GspMetadata metadata, String defaultNameSpace) {
        this.bizEntityCode = bizEntityCode;
        this.assemblyName = assemblyName;
        this.nameSpace = defaultNameSpace;
        this.isChildObj = isChildObj;
        this.objCode = objCode;
        this.bizObjectID = bizObjectID;
        if (CheckInfoUtil.checkNull(operation.getComponentId())) {
            GspMetadata compMetadata = createComponent(operation, path);
            operation.setComponentId(((GspComponent)compMetadata.getContent()).getComponentID());
            operation.setComponentName(compMetadata.getHeader().getCode());
            addReference(metadata, compMetadata);
            return operation.getCode();
        } else {
            modifyComponent(operation, path);
        }
        return null;
    }

    public GspMetadata createComponent(BizOperation operation, String path, String bizEntityCode,
        String assemblyName, boolean isChildObj, String objCode, String bizObjectID,
        String defaultNameSpace) {
        Objects.requireNonNull(operation, "operation");
        Objects.requireNonNull(path, "path");
        Objects.requireNonNull(bizEntityCode, "bizEntityCode");
        Objects.requireNonNull(assemblyName, "assemblyName");
        Objects.requireNonNull(objCode, "objCode");
        Objects.requireNonNull(bizObjectID, "bizObjectID");
        Objects.requireNonNull(defaultNameSpace, "defaultNameSpace");

        this.bizEntityCode = bizEntityCode;
        this.assemblyName = assemblyName;
        this.nameSpace = defaultNameSpace;
        this.isChildObj = isChildObj;
        this.objCode = objCode;
        this.bizObjectID = bizObjectID;
        return createComponent(operation, path);
    }

    /** 新建构件*/
    private GspMetadata createComponent(BizOperation operation, String path) {
        //1、构建实体
        GspComponent component = buildComponent();
        //2、赋值
        evaluateComponentInfo(component, operation, null);
        //3、生成构件
        GspMetadata compMetadata = establishComponent(component, path);

        return compMetadata;
    }

    private void addReference(GspMetadata refSrc, GspMetadata refTarget) {
        MetadataReference compReference = new MetadataReference();
        compReference.setMetadata(refSrc.getHeader());
        compReference.setDependentMetadata(refTarget.getHeader());
        refSrc.getRefs().add(compReference);
    }

    /**
     * 获得Java模版Package名称
     *
     * @param
     * @return
     */
    protected final String JavaModuleImportPackage(String packageName) {
        String[] strArray = packageName.split("[.]", -1);
        String str = "com.";
        int i;

        for (i = 0; i < strArray.length; i++) {
            str += strArray[i].toLowerCase() + ".";
        }
        return str;
    }

    /**
     * 获得Java模版类的名称
     *
     * @param classNamestr
     * @param packageNameStr
     * @return
     */
    protected final String JavaModuleClassName(String classNamestr, String packageNameStr) {
        String connections = "";
        if (!CheckInfoUtil.checkNull(classNamestr)) {
            connections = classNamestr.substring(classNamestr.lastIndexOf('.'));
            connections = String.format("%1$s%2$s", packageNameStr, connections);
        }

        return (connections);
    }

    /**
     * 构造构件实体类
     *
     * @return 构件实体类
     * <see cref="GspComponent"/>
     */
    protected abstract GspComponent buildComponent();

    /**
     * 为构件赋值
     *
     * @param component 构件实体信息
     * @param operation 动作信息
     */
    protected abstract void evaluateComponentInfo(GspComponent component, BizOperation operation, GspComponent originalComponent);

    /**
     * 生成构件实体对应的构件元数据
     *
     * @param component 构件实体
     * @param path      生成构件元数据指定路径
     * @return 生成的构件元数据名称
     * <see cref="string"/>
     */
    private GspMetadata establishComponent(GspComponent component, String path) {
        return GspMetadataExchangeUtil.getInstance().establishGspMetdadata(component, path, this.bizEntityCode, this.bizObjectID, this.nameSpace);
    }

    /**
     * 修改构件
     *
     * @param operation
     * @param path
     */
    private void modifyComponent(BizOperation operation, String path) {
        //1、构建实体
        GspComponent component = buildComponent();

        //3、获取要修改的构件元数据完整路径（包括后缀）
        String fullPath = "";

        ///#region ----------- 兼容旧版本命名规则（此种情况适用于构件名称未修改）--------------
        MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class);


        // 得到具体类型的构件扩展名
        String cmpExtendName = evaluateCompTypeExtendNameByOpType(operation.getOpType());
        // 带针对不同类型构件的扩展名的文件全名
        String metadataFileNameWithExtendName = operation.getComponentName() + JavaCompCodeNames.ComponentExtensionName;

        if (metadataService.isMetadataExist(path, metadataFileNameWithExtendName)) {
            //TODO
            String[] arrName = operation.getComponentName().split("[_]", -1);
            String strName = "";
            if (arrName[0].toLowerCase().equals("cmp")) {
                strName = operation.getComponentName().substring(4);
            }
            String oldFileNameWithExtendName = metadataFileNameWithExtendName;
            String newFileNameWithExtendName = metadataFileNameWithExtendName = strName + cmpExtendName;

            metadataService.renameMetadata(oldFileNameWithExtendName, newFileNameWithExtendName, path);
            operation.setComponentName(strName);
            fullPath = path + "\\" + newFileNameWithExtendName;
        } else {
            metadataFileNameWithExtendName = operation.getComponentName() + cmpExtendName;
            if (!metadataService.isMetadataExist(path, metadataFileNameWithExtendName)) {
                throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_BUSINESS_ENTITY_0001, metadataFileNameWithExtendName);
            }
            fullPath = path + "\\" + operation.getComponentName() + cmpExtendName;
        }

        ///#endregion ---------------------------兼容旧版本---------------------------

        GspComponent originalComponent = getOriginalComponent(path, metadataFileNameWithExtendName);
        //2、赋值
        evaluateComponentInfo(component, operation, originalComponent);
        //component.GetMethod().JavaPackageName = ;
        //component.GetMethod().JavaClassName = ;
        //4、修改更新构件元数据
        GspMetadataExchangeUtil.getInstance().UpdateGspMetadata(component, fullPath, this.bizEntityCode, this.bizObjectID, this.nameSpace);
    }

    /**
     * 获取修改元数据之前的元数据信息
     *
     * @param path
     * @param
     * @param metadataFileNameWithSuffix
     * @return
     */
    private GspComponent getOriginalComponent(String path, String metadataFileNameWithSuffix) {
        MetadataService metadataService = SpringBeanUtils.getBean(MetadataService.class);
        GspMetadata metadata = metadataService.loadMetadata(metadataFileNameWithSuffix, path);
        //TODO GspComponentMetadata 对应J版无对应的类，确认一下是否还需要
//		if (metadata.getContent() instanceof GspComponentMetadata)
//		{
//			ComponentSerializer serializer = new ComponentSerializer();
//			Object tempVar = ((IMetadataContentSerializer)((serializer instanceof IMetadataContentSerializer) ? serializer : null)).DeSerialize((JObject)JToken.Parse(((GspComponentMetadata)((metadata.Content instanceof GspComponentMetadata) ? metadata.Content : null)).ContentString));
//			GspComponent originalComponent = (GspComponent)((tempVar instanceof GspComponent) ? tempVar : null);
//			return originalComponent;
//		}
//		else
//		{
        GspComponent originalComponent = (GspComponent) ((metadata.getContent() instanceof GspComponent) ? metadata.getContent() : null);
        return originalComponent;
//		}
    }

    private String evaluateCompTypeExtendNameByOpType(BEOperationType opType) {
        switch (opType) {
            case BizAction:
                return JavaCompCodeNames.BECmpExtendName;
            case BizMgrAction:
                return JavaCompCodeNames.BEMgrCmpExtendName;
            case Determination:
                return JavaCompCodeNames.DtmCmpExtendName;
            case Validation:
                return JavaCompCodeNames.ValCmpExtendName;
            default:
                throw BusinessEntityException.createException(BusinessEntityErrorCodeEnum.GSP_BEMODEL_ENUM_NOTSUPPORT_0007, opType.getClass().getSimpleName());
        }
    }
}
